home *** CD-ROM | disk | FTP | other *** search
- Subject: v24i066: Purdue software product installation system, Part04/07
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 573916ad 877ae86d 6b5c3b8c cb1503a1
-
- Submitted-by: Kevin Braunsdorf <ksb@nostromo.cc.purdue.edu>
- Posting-number: Volume 24, Issue 66
- Archive-name: pucc-install/part04
-
- Submitted-by: ksb@cc.purdue.edu (Kevin Braunsdorf)
- Archive-name: pucc-1b/part04
-
- #!/bin/sh
- # This is part 04 of pucc-1b
- # ============= install.d/install.1l ==============
- if test ! -d 'install.d'; then
- echo 'x - creating directory install.d'
- mkdir 'install.d'
- fi
- if test -f 'install.d/install.1l' -a X"$1" != X"-c"; then
- echo 'x - skipping install.d/install.1l (File already exists)'
- else
- echo 'x - extracting install.d/install.1l (Text)'
- sed 's/^X//' << 'Purdue' > 'install.d/install.1l' &&
- .\" $Id: install.1l,v 7.0 90/09/17 09:41:50 ksb Exp $
- .\" Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
- .\" 47907. All rights reserved.
- .\"
- .\" Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
- .\" Jeff Smith, jsmith@cc.purdue.edu, purdue!jsmith
- .\"
- .\" This software is not subject to any license of the American Telephone
- .\" and Telegraph Company or the Regents of the University of California.
- .\"
- .\" Permission is granted to anyone to use this software for any purpose on
- .\" any computer system, and to alter it and redistribute it freely, subject
- .\" to the following restrictions:
- .\"
- .\" 1. Neither the authors nor Purdue University are responsible for any
- .\" consequences of the use of this software.
- .\"
- .\" 2. The origin of this software must not be misrepresented, either by
- .\" explicit claim or by omission. Credit to the authors and Purdue
- .\" University must appear in documentation and sources.
- .\"
- .\" 3. Altered versions must be plainly marked as such, and must not be
- .\" misrepresented as being the original software.
- .\"
- .\" 4. This notice may not be removed or altered.
- .\"
- .\" $Laser: ${tbl-tbl} %f | ${ltroff-ltroff} -man
- .\" $Compile: ${tbl-tbl} %f | ${nroff-nroff} -man | ${PAGER-${more-more}}
- .TH INSTALL 1L PUCC
- .SH NAME
- install \- update files or directories in a controlled environment
- .SH SYNOPSIS
- \fBinstall\fP [\-\fB1Dclnpqsv\fP] [\-\fBC\fP\fIchecklist\fP] [\-\fBH\fP\fIhardlinks\fP] [\-\fBS\fP\fIsymlinks\fP] [\-\fBg\fP\fIgroup\fP] [\-\fBm\fP\fImode\fP] [\-\fBo\fP\fIowner\fP] \fIfiles\fP \fIdestination\fP
- .sp 1
- \fBinstall\fP \-\fBd\fP [\-\fBhnqrv\fP] [\-\fBC\fP\fIchecklist\fP] [\-\fBg\fP\fIgroup\fP] [\-\fBm\fP\fImode\fP] [\-\fBo\fP\fIowner\fP] \fIdirectory\fP
- .sp 1
- \fBinstall\fP \-[\fBhV\fP] [\-\fBC\fP\fIchecklist\fP]
- .sp 1
- \fBinstall\fP \-\fBR\fP [\-\fB1dlnqsv\fP] [\-\fBC\fP\fIchecklist\fP] [\-\fBH\fP\fIhardlinks\fP] [\-\fBS\fP\fIsymlinks\fP] [\-\fBg\fP\fIgroup\fP] [\-\fBm\fP\fImode\fP] [\-\fBo\fP\fIowner\fP] \fIdestination\fP
- .SH DESCRIPTION
- .PP
- .I Install
- is a tool for updating system files in a controlled environment.
- The design philosophy of
- .I install
- is to automate the installation process and put
- it as much out of reach of human carelessness as possible, while
- providing a flexible, easy to use tool.
- .I Install
- provides the following features:
- .IP \(bu
- .I Install
- increases system security by providing a controlled installation
- environment. It checks the actions of the superuser against a
- configuration file that you build (either by hand or using
- .IR instck (1L)),
- and can prevent grievous mistakes such as installing a shell setuid
- to a privileged user, or installing a world\(hywritable password file.
- An appropriate configuration file can guarantee that files are
- installed with correct owner, group and mode, that
- .IR strip (1)
- is run on binaries and
- .IR ranlib (1)
- is run on libraries.
- Regardless of whether you create a configuration file,
- .I install
- warns you of many possible errors, unless you make it quiet
- with its
- .B \-q
- option. For instance, if you install
- a new version of the
- .IR ex (1)
- editor and forget to update its links,
- .I install
- will notice the extra links to the existing version and warn
- you that you might be making a mistake.
- .IP \(bu
- Installed files do not overwrite current versions. The current version
- is backed up to a subdirectory of its dot directory (named \*(lqOLD\*(rq by
- default), where it may be easily
- re\(hyinstalled in the case of an unforeseen bug. The companion program
- .IR purge (1L)
- removes these backed\(hyup files after a user\(hyspecified interval.
- By default, if you repeatedly install new versions of a file,
- .I install
- creates a series of backups, providing a primitive form of version
- control.
- .IP \(bu
- .I Install
- increases accountability by logging the actions of the superuser.
- This makes it easier to track down errors after the fact.
- .IP \(bu
- .I Install
- simplifies Makefiles by allowing you to combine operations that
- would require several steps into a single one (e.g., you can specify
- in a single command line a file's ownership, group, mode, whether to run
- .IR strip (1)
- or
- .IR ranlib (1),
- and which hard or soft links should be made).
- .IP \(bu
- Despite its power and potential complexity,
- .I install
- is easy to use interactively because it intuits appropriate
- installation parameters for you, either by using those associated with
- an existing file, or its compilation\(hydependent defaults. In most
- cases you do not have to specify a file's owner, group, or mode unless
- you want them to be different from an existing file or the
- compilation\(hydependent defaults.
- Typical interactive usage is simply \*(lqinstall file destination.\*(rq
- .IP \(bu
- .I Install
- is as careful as it can be to complete an installation once it is
- begun. There is a point in the code where
- .IR unlink (2)
- and
- .IR rename (2)
- must be executed in close succession, and that is the only window in
- which a system crash or a signal might leave system files in
- an inconsistent state (unfortunately, this is not true under operating
- systems that do not provide an atomic
- .IR rename (2)
- system call).
- This is true even when
- .I install
- must copy files across file system boundaries.
- .IP \(bu
- .I Install
- may also be used to remove (de\(hyinstall) files in a controlled manner.
- .IP \(bu
- Finally,
- .I install
- currently runs on a variety of architectures and operating systems
- and is easy to port to new platforms.
- .SH USAGE
- .SS Terminology
- .PP
- The user specifies one or more
- .I files
- to install, and a
- .IR destination ,
- which may be either a full or relative pathname ending
- in a file name or an existing directory name (if the
- directory does not exist,
- .I install
- thinks you mean to create a new file).
- The special name \*(lq\-\*(rq may be used for the
- .I file
- argument to indicate stdin (see EXAMPLES). In this case,
- .I destination
- .B must not
- be a directory, since
- .I install
- cannot guess the name the file should have when installed.
- .PP
- Because the user may specify more than one
- .IR files ,
- and
- .I destination
- may be an existing directory or a file which may or may not
- exist,
- .I install
- must also internally keep track of a
- .I destdir
- (\*(lqdestination directory\*(rq, i.e., the directory in which to
- place the file to install), and a
- .IR target
- (the full pathname that each file to install
- will have when it is installed in
- .IR destdir ).
- The
- .I target
- and
- .I destdir
- are constructed from the
- .I files
- and
- .I destination
- arguments as described below.
- .PP
- For each name in
- .IR files ,
- .I install
- determines a
- .I target
- name as follows:
- If
- .I destination
- is an existing directory,
- .I install
- catenates the last component of
- .I file
- to
- .I destination
- to arrive at the
- .I target
- name. If
- .I destination
- does not exist or is an existing file,
- .I install
- takes
- .I destination
- to be the
- .IR target .
- In the latter case
- .I destdir
- is simply
- .I destination
- minus its last component.
- If this reduction leaves
- .I destdir
- empty then it is set to \*(lq.\*(rq.
- (E.g., if
- .I destination
- were
- .I /etc/motd
- then
- .I destdir
- would be
- .IR /etc ,
- but if
- .I destination
- were just
- .I motd
- then
- .I destdir
- would be \*(lq.\*(rq.)
- N.B.: If more than one
- .I files
- are specified,
- .I destination
- .B must
- be an existing directory.
- .PP
- Examples are the easiest way to clarify this terminology.
- .RS
- .sp 1
- In the command \*(lqinstall motd /etc/motd\*(rq:
- .sp 1
- .RS
- .TS
- l l .
- file: motd
- destination: /etc/motd
- destdir: /etc
- target: /etc/motd
- .TE
- .RE
- .sp 1
- In the command \*(lqinstall motd /etc\*(rq:
- .sp 1
- .RS
- .TS
- l l .
- file: motd
- destination: /etc
- destdir: /etc
- target: /etc/motd
- .TE
- .RE
- .sp 1
- In the command sequence \*(lqcd /etc; install motd.new motd\*(rq:
- .sp 1
- .RS
- .TS
- l l .
- file: motd.new
- destination: motd
- destdir: . (dot)
- target: ./motd
- .TE
- .RE
- .RE
- .sp 1
- .SS Installation Parameters
- .PP
- If the file permissions, ownership or group ownership are not specified on
- the command line and
- .I target
- exists,
- .I install
- duplicates its group, ownership, and mode.
- Otherwise, if the
- .I target
- doesn't exist and the invoker is the superuser,
- .I install
- uses its compilation\(hydependent defaults.
- Otherwise,
- .I install
- uses the effective uid, the effective gid,
- and a compilation\(hydependent mode.
- .I Install
- may also be configured to inherit the mode and ownerships
- from the
- .IR destdir .
- (Use the
- .B \-V
- option to view the compilation\(hydependent defaults.)
- .PP
- Note:
- .I install
- can only change ownership if invoked by the superuser;
- however, any user may specify a different group
- as long as the group is allowed by
- .IR chgrp (1).
- .SS Method of Operation
- .PP
- .I Install
- first checks the proposed owner, group, and mode against the
- configuration file. It also checks whether the
- .I target
- should have
- .IR strip (1)
- or
- .IR ranlib (1)
- run on it after installation.
- .I Install
- aborts if it finds discrepancies between the configuration
- file and the proposed installation parameters. (If necessary,
- you can override the configuration file
- with \*(lq\fB\-C\fP \fI/dev/null\fP.\*(rq)
- .PP
- .I Install
- then looks for an existing
- .I target
- and backs it up to a subdirectory of
- .I destdir
- named \*(lqOLD\*(rq, which
- .I install
- will create if it doesn't exist.
- The backup is actually just a hard link to the existing
- .IR target .
- (If a backup file of the same name already exists in \*(lqOLD\*(rq,
- .I install
- first renames it by appending its process id).
- For security reasons,
- .I install
- drops setuid and setgid bits when files are moved to the \*(lqOLD\*(rq
- directory.
- After backing up an existing
- .IR target ,
- .I install
- temporarily moves
- .I file
- to
- .IR destdir/OLD/random-name .
- This step is taken to ensure that both
- .I file
- and
- .I target
- are in the same file system so that
- .IR rename (2)
- may be used for the final installation. This reduces the window
- in which files might be left in an inconsistent state due to a
- system crash or signal. Consequently the \*(lqOLD\*(rq
- subdirectory must not be a file system mount point, since the
- .IR rename (2)
- would fail.
- .PP
- .I Install
- then unlinks the existing
- .I target
- (leaving the backup) and renames
- .IR destdir/OLD/random-name
- to
- .IR target .
- .PP
- Next
- .I install
- updates any hard links and soft (symbolic) links
- given under the
- .B \-H
- or
- .B \-S
- options. All links point at the
- installed
- .IR target .
- Existing symbolic links which point to the
- correct file are left unchanged, otherwise removed and
- replaced with the correct spelling. Existing correct hard links
- are unlinked and replaced, without a
- backup. Links which point to a file other than the
- .I target
- are backed up to \*(lqOLD\*(rq and linked.
- .I Install
- prints a warning in this case.
- .SH OPTIONS
- .TP
- .B \-1
- After a successful installation
- .I install
- removes any previous
- backup in \*(lqOLD\*(rq.
- Thus
- .I install
- will keep exactly one previous revision of
- the installed file.
- .TP
- .B \-c
- Do not unlink the
- .IR files .
- .TP
- .BI \-C checkfile
- Search
- .I checkfile
- for an expression that matches the
- .IR target .
- If
- .I install
- finds such an expression it will check the proposed modes (etc.)
- against those listed in the checkfile; any differences cause
- .I install
- to abort the installation.
- This mechanism is provided to protect the superuser from installing,
- for instance, the shell setuid root, as in:
- .br
- .sp 1
- .in 1.5i
- install \-m7555 \-o root \-g wheel sh /bin
- .sp 1
- .in -.5i
- .br
- (note the extra \*(lq5\*(rq).
- See
- .IR install.cf (5L)
- and
- .IR instck (1L).
- .TP
- .BI \-d
- Build a directory rather than a plain file.
- If the directory is an OLD directory it is built with appropriate modes
- (see
- .B \-V
- below).
- .TP
- .B \-D
- Don't back up an existing
- .I target
- (the \*(lqDestroy\*(rq option).
- This is useful when a trivially correctable problem such as a
- spelling error in a print statement is found in a recently installed
- product, or when the
- .I target
- can be regenerated easily and is installed frequently. Sites that
- do not wish to keep backups but still want to take advantage of the
- checkfile could set this option in the environment.
- .TP
- .BI \-g group
- Install the file with group ownership
- .IR group .
- If no
- .B \-g
- option is given
- .I install
- will decide the group to use:
- .br
- .in 1.5i
- \(bu if there is an existing
- .I target
- use its group
- .br
- \(bu if we are the superuser use a compilation\(hydependent group
- .br
- \(bu else use the effective group id
- .TP
- .in -.5i
- .B \-h
- Print a summary of
- .IR install 's
- usage (the \*(lqhelp\*(rq option).
- .TP
- .BI \-H hardlinks
- Specify a colon separated list of hard links
- that should be made to the
- .I target
- after it is installed.
- (See EXAMPLES below.)
- .TP
- .BI \-l
- Run
- .IR ranlib ( 1 )
- on the installed
- .IR targets .
- Under System V this option has no significance, but
- .B must
- be given to pass the default checkfile
- (see
- .IR install.cf (5L)).
- This allows Makefiles to work under all versions of UNIX.
- .TP
- .BI \-m mode
- Install the file with permissions
- .IR mode .
- .I Mode
- may be given in either octal mode or
- in the symbolic form used by
- .IR ls (1)
- (e.g., \*(lq755\*(rq) is equivalent to \*(lqrwxr-xr-x\*(rq).
- If the
- .B \-m
- option is not given,
- .I install
- will decide the mode to use:
- .br
- .in 1.5i
- \(bu if there is an existing
- .I target
- use its mode
- .br
- \(bu if we are the superuser use a compilation\(hydependent mode
- .br
- \(bu else use a compilation\(hydependent user mode
- .in -.5i
- .TP
- .B \-n
- Give an approximate execution trace by printing the (almost) equivalent
- shell commands, but don't do anything.
- This is useful for debugging
- .I install
- or seeing what a
- difficult command line would do if you ran it.
- .TP
- .BI \-o owner
- Change ownership of
- .I file
- to
- .I owner
- (superuser only).
- If no
- .B \-o
- option is given
- .I install
- will decide the owner to use:
- .br
- .in 1.5i
- \(bu if there is an existing
- .I target
- use its owner
- .br
- \(bu if we are the superuser use a compilation\(hydependent owner
- .br
- \(bu else use our effective uid
- .TP
- .in -.5i
- .B \-p
- Preserve the time stamp of
- .I files
- in
- .IR targets .
- .TP
- .B \-q
- Normally
- .I install
- informs you about a variety of possible errors. This option
- turns off that behavior and is not recommended except for
- special circumstances. Caveat emptor.
- .TP
- .B \-r
- Under
- .B \-d
- build all intervening directories between \*(lq/\*(rq
- and
- .IR destination.
- .TP
- .B \-R
- Remove (de\(hyinstall) a file by moving it into the OLD
- subdirectory. A temporary shell script is created to replace
- the
- .IR target ,
- installed (which removes the existing
- .I target
- to \*(lqOLD\*(rq), and removed.
- .TP
- .B \-s
- Run
- .IR strip (1)
- on the installed
- .IR targets .
- .TP
- .BI \-S symlinks
- Specify a colon separated list of symbolic links that
- .I install
- should
- point at the installed file. (See EXAMPLES below.)
- .TP
- .B \-v
- Be verbose. Run
- .IR ls (1)
- on the backed up file and the
- .IR target .
- Notify the user of all side effects of this installation.
- .TP
- .B \-V
- View
- .IR install 's
- version and compilation\(hydependent owner, group and mode tables.
- .SH EXAMPLES
- .TP
- install motd /etc
- Install
- .I motd
- as
- .IR /etc/motd .
- If
- .I /etc/motd
- exists move it to
- .I /etc/OLD/motd
- and duplicate its
- ownership, group and mode; otherwise,
- use defaults. Create the directory
- .I /etc/OLD
- if it does not exist.
- .TP
- install \-c1 \-m 755 foo.sh /etc/foo
- Install
- .IR foo.sh .
- as
- .IR /etc/foo .
- Do not unlink
- .I foo.sh
- after the installation. Set permissions appropriate for a shell script on
- .IR /etc/foo .
- If
- .I /etc/OLD/foo
- exists, overwrite it instead of moving it to a new name (i.e., retain a
- single backup of
- .I /etc/foo
- in
- .IR /etc/OLD ).
- .TP
- install foo bar baz /usr/lib
- Install the files
- .IR foo ,
- .I bar
- and
- .I baz
- as
- .IR /usr/lib/foo ,
- .IR /usr/lib/bar ,
- and
- .IR /usr/lib/baz .
- Use the modes of the existing files or defaults.
- .TP
- install \-vsm6751 \-oroot \-gkmem sendmail /usr/lib
- Install
- .I sendmail
- as
- .IR /usr/lib/sendmail ,
- owned by root, grouped to kmem, and with
- the setuid and setgid permission bits set.
- Strip
- .I /usr/lib/sendmail
- after its installation and be verbose.
- .TP
- install \-d \-m \-rwxrwxrwt /tmp
- Build the directory
- .I /tmp
- with the default owner and group,
- mode 777, and with the \*(lqsticky\*(rq bit set.
- .TP
- install \-c \-m1755 \-Hview:vi:edit:e:/usr/bin/ex a.out /usr/ucb/ex
- Install the
- .I ex
- editor with all of its hard links
- .RI ( /usr/ucb/view ,
- .IR /usr/ucb/vi ,
- .IR /usr/ucb/edit ,
- .IR /usr/ucb/e ,
- .RI and /usr/bin/ex ).
- Replacing
- .B \-H
- with
- .B \-S
- would cause
- .I install
- to build symbolic links on machines which support them.
- .TP
- install \-d \-r /usr/local/lib/mk
- Recursively build any and all of the directories
- .IR /usr ,
- .IR /usr/local ,
- .IR /usr/local/lib ,
- and
- .I /usr/local/lib/mk
- that do not already exist. Silently do nothing if they
- already exist (useful in Makefiles).
- .TP
- install \-V
- Output the version of install and a table of compiled in defaults.
- Output when run as the superuser might look similar to this,
- depending on the compilation defaults:
- .RS
- .TS
- l s s
- l s s
- l l l.
- install: version: $\&Id: main.c,v 6.7 64/02/15 16:21:41 ksb Exp $
- install: configuration file: /usr/local/etc/install.cf
- install: syslog facility: 144
- install: superuser defaults:
- install: owner is file=root dir=root OLD=root
- install: group is file=binary dir=binary OLD=binary
- install: mode is file=0755 dir=0755 OLD=inherited
- .TE
- .RE
- .TP
- rsh some.other.host install \- /etc/motd < motd.some.other.host
- This example shows a way to use \*(lq\-\*(rq to advantage. It is
- often useful when
- .IR rdist (1)
- is overkill or otherwise inappropriate. For instance, if you had
- a Makefile that generated files named
- .IR host1.motd ,
- .IR host2.motd ,
- .IR host3.motd ,
- etc., and wanted to install them on those hosts, you could do
- something like this:
- .sp 1
- .nf
- .na
- .KS
- .RS
- for host in host1 host2 host3; do
- .RS
- rsh $host install \- /etc/motd < $host.motd
- .RE
- done
- .KE
- .RE
- .fi
- .ad
- .sp 1
- .SH DIAGNOSTICS
- .KS
- .PP
- Unless made quiet by
- .BR \-q ,
- .I install
- will warn the installer if:
- .RS
- .br
- \(bu the owner, group, or mode changes
- .br
- \(bu the setuid, setgid, or sticky bits change
- .br
- \(bu a setuid program is loaded with the \*(lq#!\*(rq magic number
- .br
- \(bu \fItarget\fP does not exist (this is a prophylactic against
- typographical errors\(emsee CAVEATS below)
- .KE
- .RE
- .PP
- .KS
- .I Install
- will abort the installation if:
- .RS
- .br
- \(bu
- .I install
- cannot make a backup of an existing
- .I target
- .br
- \(bu a setuid program\'s owner was not specified with the mode
- .br
- \(bu a setgid program\'s group was not specified with the mode
- .br
- \(bu the specified owner, group, or mode failed to match the checkfile
- .br
- \(bu the superuser installs a setuid program that is not in the checkfile
- (this is a compile time option)
- .RE
- .KE
- .SH ENVIRONMENT
- .PP
- The environment variable
- .B INSTALL
- may be used to
- set command line options.
- Such options are read before any explicit command line options, e.g.
- .br
- .RS
- .sp 1
- INSTALL=-v ; export INSTALL
- .sp 1
- .RE
- .br
- will turn on \*(lqverbose\*(rq mode for all subsequent
- invocations of
- .IR install .
- .SH BUGS
- .PP
- .I Install
- does not use file locking, so it's possible for two competing
- .I install
- processes to lose data.
- .PP
- The trace option
- .RB ( \-n )
- doesn't always show exactly what
- .I install
- would do. It will show OLD directories being made several times, and
- inherited modes don't propagate correctly under
- .BR \-drn .
- .SH CAVEATS
- .PP \(bu
- .I Install
- will not build character special files.
- Use
- .IR mknod (8)
- instead.
- .PP
- If /bin doesn't exist, the command:
- .sp 1
- .RS
- install ls /bin
- .RE
- .sp 1
- will make
- .I /bin
- be a copy of the binary
- .IR ls .
- This is an unavoidable consequence of allowing the
- .I destination
- to be a directory.
- You can avoid this by
- using \*(lqinstall \-d \fIdirectory\fP\*(rq in Makefiles to ensure
- that destination directories exist, e.g.,
- .sp 1
- .nf
- .na
- .RS
- install: product
- .RS
- install -d /bin
- install product /bin
- .RE
- .RE
- .fi
- .ad
- .sp 1
- .I Install
- does nothing and exits normally if the directory already exists,
- so it's safe to include lines like this in your Makefiles.
- You can also use
- .IR instck (1L)
- to ensure that all system
- directories are built correctly.
- .PP \(bu
- .I Install
- can cover up mistakes of omission in Makefiles by copying the modes
- on a previously installed target.
- For example, the invocation of
- .I install
- in a Makefile might not specify that the
- .I destination
- should be setuid root, but
- as long as the
- .I target
- existed
- .I install
- would hide the error by
- copying the modes of the existing
- .IR target .
- The problem in the Makefile would not be found unless the
- .I target
- were removed prior to installation.
- Use
- .IR instck (1L)
- to generate a configuration file to avoid this problem.
- .PP \(bu
- .I Install
- and
- .IR purge (1L)
- assume that they own the file namespace in the \*(lqOLD\*(rq
- subdirectories. If other programs create, modify or delete
- files in the \*(lqOLD\*(rq subdirectories, they will probably
- collide with one of
- .I install
- or
- .IR purge (1L)
- eventually.
- .SH FILES
- .TS
- l l.
- /usr/local/lib/install.cf the default check list file
- .../OLD/#inst* temporary files made for installations
- .../OLD/#bogus* links made to running binaries to avoid ETXTBSY
- .../OLD/* copies of previously installed files
- .TE
- .SH AUTHORS
- Kevin Braunsdorf, Purdue University Computing Center (ksb@cc.purdue.edu)
- .br
- Jeff Smith, Purdue University Computing Center (jsmith@cc.purdue.edu)
- .br
- Copyright \*(co 1990 Purdue Research Foundation. All rights reserved.
- .SH "SEE ALSO"
- chgrp(1), instck(1L), ls(1), make(1), ranlib(1), strip(1),
- intro(2),
- syslog(3),
- install.cf(5L),
- chown(8), mknod(8), purge(8L)
- Purdue
- chmod 0444 install.d/install.1l ||
- echo 'restore of install.d/install.1l failed'
- Wc_c="`wc -c < 'install.d/install.1l'`"
- test 21337 -eq "$Wc_c" ||
- echo 'install.d/install.1l: original size 21337, current size' "$Wc_c"
- fi
- # ============= purge/purge.c ==============
- if test ! -d 'purge'; then
- echo 'x - creating directory purge'
- mkdir 'purge'
- fi
- if test -f 'purge/purge.c' -a X"$1" != X"-c"; then
- echo 'x - skipping purge/purge.c (File already exists)'
- else
- echo 'x - extracting purge/purge.c (Text)'
- sed 's/^X//' << 'Purdue' > 'purge/purge.c' &&
- /*
- X * a C version of purge(8L) (ksb)
- X *
- X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
- X * 47907. All rights reserved.
- X *
- X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
- X *
- X * This software is not subject to any license of the American Telephone
- X * and Telegraph Company or the Regents of the University of California.
- X *
- X * Permission is granted to anyone to use this software for any purpose on
- X * any computer system, and to alter it and redistribute it freely, subject
- X * to the following restrictions:
- X *
- X * 1. Neither the authors nor Purdue University are responsible for any
- X * consequences of the use of this software.
- X *
- X * 2. The origin of this software must not be misrepresented, either by
- X * explicit claim or by omission. Credit to the authors and Purdue
- X * University must appear in documentation and sources.
- X *
- X * 3. Altered versions must be plainly marked as such, and must not be
- X * misrepresented as being the original software.
- X *
- X * 4. This notice may not be removed or altered.
- X *
- X *
- X * The old shell version of purge suffered from 4 problems:
- X *
- X * 1\ it used the -ctime option to find that is local to PUCC
- X *
- X * 2\ it didn't handle symbolic links correctly
- X *
- X * 3\ it didn't handle error conditions well (st_nlink > 1)
- X *
- X * 4\ it was not useful to general users
- X *
- X * READ THIS! N.B. if you want to change purge:
- X *
- X * Do *NOT* change purge to delete empty OLD dirs. This will race
- X * with install and cause install the fail. (As is won't build the
- X * OLD dir, the dir will go away, install will try to build a link
- X * in it and fail.)
- X */
- #include <sys/param.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/file.h>
- #include <sys/time.h>
- X
- #include <pwd.h>
- #include <grp.h>
- #include <errno.h>
- #include <ctype.h>
- #include <stdio.h>
- X
- #include "configure.h"
- #include "install.h"
- #include "purge.h"
- #include "filedup.h"
- #include "main.h"
- X
- #if BSDDIR
- #include <sys/dir.h>
- #else
- #include <ndir.h>
- #endif
- X
- #if !defined(ENAMETOOLONG)
- #define ENAMETOOLONG E2BIG
- #endif
- X
- extern char *malloc(), *realloc(), *strcpy(), *strrchr();
- X
- #ifndef lint
- static char copyright[] =
- "@(#) Copyright 1990 Purdue Research Foundation.\nAll rights reserved.\n";
- #endif
- X
- static time_t
- X tCutOff, /* the last install time we keep */
- X tCopyKeep; /* last temp copy to keep */
- static char acRoot[] = /* could be "root" "lroot" or "0" */
- X DEFDIROWNER;
- static char acOld[] = /* the name of our OLD dirs */
- X OLDDIR;
- static char acBogus[] = /* component key for busy links */
- X TMPBOGUS;
- static char acCopy[] = /* component key for temp copies */
- X TMPINST;
- static FILEDUPS FDLinks; /* hard links database */
- static int
- X bHaveRoot, /* are effective uid lets us be root */
- X iCopy, /* strlen of acCopy */
- X iBogus; /* strlen of acBogus */
- X
- #define LSTAT lstat
- X
- struct {
- X int size; /* the size of the uid array itself */
- X int count; /* number of ids we are keeping */
- X uid_t *puids; /* the uid array we are keeping */
- X char **ppclogins; /* the login names we found */
- } ids = {0, 0, (uid_t *)0};
- X
- /* this routine should check for all the OLD dir owners (ksb)
- X * (like `root', `news', `ingress', etc)
- X */
- int
- isSysId(uid)
- uid_t uid;
- {
- X register int j;
- X
- X if (fAnyOwner)
- X return 1;
- X for (j = 0; j < ids.count; ++j) {
- X if (ids.puids[j] == uid) {
- X return 1;
- X }
- X }
- X return 0;
- }
- X
- /*
- X * is a string all digits (ksb)
- X */
- int
- AllDigits(pcTemp)
- char *pcTemp;
- {
- X for (; '\000' != *pcTemp; ++pcTemp) {
- X if (!isdigit(*pcTemp))
- X return 0;
- X }
- X return 1;
- }
- X
- /*
- X * this routine adds a new valid OLD dir owner to the list (ksb)
- X */
- int
- AddHer(pcLogin)
- char *pcLogin;
- {
- X register int j;
- X register struct passwd *pwdAdd;
- X
- X if (AllDigits(pcLogin)) {
- X if ((struct passwd *)0 == (pwdAdd = getpwuid(atoi(pcLogin)))) {
- X fprintf(stderr, "%s: getpwuid: %s: %s\n", progname, pcLogin, strerror(errno));
- X return 1;
- X }
- X } else if ((struct passwd *)0 == (pwdAdd = getpwnam(pcLogin))) {
- X fprintf(stderr, "%s: getpwname: %s: %s\n", progname, pcLogin, strerror(errno));
- X return 1;
- X }
- X if (ids.size < ids.count+1) {
- X ids.size += 8;
- X if ((uid_t *)0 == ids.puids) {
- X ids.puids = (uid_t *)malloc(ids.size*sizeof(uid_t));
- X } else {
- X ids.puids = (uid_t *)realloc((char *)ids.puids, ids.size*sizeof(uid_t));
- X }
- X if ((char **)0 == ids.ppclogins) {
- X ids.ppclogins = (char **)malloc(ids.size*sizeof(char *));
- X } else {
- X ids.ppclogins = (char **)realloc((char *)ids.ppclogins, ids.size*sizeof(char *));
- X }
- X if ((uid_t *)0 == ids.puids || (char **)0 == ids.ppclogins) {
- X fprintf(stderr, "%s: out of memory in realloc\n", progname);
- X exit(2);
- X }
- X }
- X for (j = 0; j < ids.count; ++j) {
- X if (ids.puids[j] != pwdAdd->pw_uid) {
- X continue;
- X }
- X return 0;
- X }
- X ids.puids[j] = pwdAdd->pw_uid;
- X ids.ppclogins[j] = pcLogin;
- X ++ids.count;
- X return 0;
- }
- X
- /*
- X * this routine added the default user (the envoker) to the OLD (ksb)
- X * owners list (set up the time flags too)
- X */
- void
- InitAll()
- {
- X register char *pcUser, *pcX;
- X struct passwd *pwdUser;
- X extern char *getenv();
- X extern long time();
- X
- X /* remove the XXXXX from the mktemp templates
- X */
- X pcX = acBogus + (sizeof(acBogus)-2);
- X while ('X' == *pcX)
- X *pcX-- = '\000';
- X pcX = acCopy + (sizeof(acCopy)-2);
- X while ('X' == *pcX)
- X *pcX-- = '\000';
- X iBogus = strlen(acBogus);
- X iCopy = strlen(acCopy);
- X
- X FDInit(& FDLinks);
- X if (0 == getuid())
- X fSuperUser = 1;
- X (void)time(&tCutOff);
- X tCopyKeep = tCutOff - ((time_t)(60*60*24));
- X tCutOff -= ((time_t)(60*60*24))*iDays;
- X
- X (void)setpwent();
- X
- X bHaveRoot = 0 == geteuid();
- X
- #if defined(INST_FACILITY)
- X if (bHaveRoot && fExec) {
- X openlog(progname, 0, INST_FACILITY);
- X }
- #endif
- X if (fSuperUser) {
- X (void)AddHer(acRoot);
- X return;
- X }
- X
- X pcUser = getenv("USER");
- X if ((char *)0 == pcUser || '\000' == pcUser[0]) {
- X pcUser = getenv("LOGNAME");
- X }
- X if ((char *)0 == pcUser || '\000' == pcUser[0]) {
- X if ((struct passwd *)0 == (pwdUser = getpwuid(getuid()))) {
- X fprintf(stderr, "%s: getpwuid: %d: %s\n", progname, getuid(), strerror(errno));
- X exit(1);
- X }
- X pcUser = pwdUser->pw_name;
- X }
- X pcUser = strcpy(malloc((strlen(pcUser)|7)+1), pcUser);
- X (void)AddHer(pcUser);
- }
- X
- X
- /*
- X * show the user what we are compiled to do, as best we can (ksb)
- X */
- int
- Version()
- {
- X register int i;
- X
- X printf("%s: $Id: purge.c,v 3.1 90/11/26 12:26:41 ksb Exp $\n", progname);
- X printf("%s: default superuser login name: %s\n", progname, acRoot);
- X printf("%s: backup directory name: %s\n", progname, acOld);
- X printf("%s: valid backup directory owner", progname);
- X if (fAnyOwner) {
- X printf(": <any>");
- X } else {
- X if (ids.count > 1)
- X printf("s");
- X for (i = 0; i < ids.count; ++i)
- X printf("%c %s", i == 0 ? ':' : ',', ids.ppclogins[i]);
- X }
- #if defined(INST_FACILITY)
- X printf("\n%s: syslog facility %d\n", progname, INST_FACILITY);
- #else
- X printf("\n");
- #endif
- X return 0;
- }
- X
- X
- /*
- X * get the user-level name for this node `plain file' or `socket' (ksb)
- X * return string, ref-out single char
- X */
- char *
- NodeType(mType, pcChar)
- unsigned int mType;
- char *pcChar;
- {
- X auto char acWaste[2];
- X
- X if ((char *)0 == pcChar)
- X pcChar = acWaste;
- X
- X switch (mType & S_IFMT) {
- X case S_IFDIR:
- X *pcChar = 'd';
- X return "directory";
- #if defined(S_IFSOCK)
- X case S_IFSOCK:
- X *pcChar = 's';
- X return "socket";
- #endif /* no sockets */
- #if defined(S_IFIFO)
- X case S_IFIFO:
- X *pcChar = 'p';
- X return "fifo";
- #endif
- #if HAVE_SLINKS
- X case S_IFLNK:
- X *pcChar = 'l';
- X return "symbolic link";
- #endif
- X case S_IFBLK:
- X *pcChar = 'b';
- X return "block device";
- X case S_IFCHR:
- X *pcChar = 'c';
- X return "character device";
- X case S_IFREG:
- X case 0:
- X *pcChar = '-';
- X return "plain file";
- X default:
- X break;
- X }
- X *pcChar = '?';
- X return "type unknown";
- }
- X
- /*
- X * avoid putting . and .. in the dirs to check, we would loop (ksb)
- X */
- int
- DotSel(pDE)
- struct direct *pDE;
- {
- X register char *pcName = pDE->d_name;
- X
- X return ! ('.' == pcName[0] && ('\000' == pcName[1] || '.' == pcName[1] && '\000' == pcName[2]));
- }
- X
- /*
- X * remove the file, or fake the removal (ksb)
- X */
- void
- Remove(pcFile)
- char *pcFile;
- {
- X if (fVerbose) {
- X printf("%s: rm -f %s\n", progname, pcFile);
- X }
- X if (fExec && -1 == unlink(pcFile)) {
- #if defined(INST_FACILITY)
- X if (EBUSY == errno && fExec && bHaveRoot) {
- X syslog(LOG_INFO, "still busy `%s\'", pcFile);
- X }
- #endif
- X fprintf(stderr, "%s: unlink: %s: %s\n", progname, pcFile, strerror(errno));
- X return;
- X }
- #if defined(INST_FACILITY)
- X if (fExec && bHaveRoot) {
- X syslog(LOG_INFO, "rm `%s\'", pcFile);
- X }
- #endif
- }
- X
- /*
- X * purge an OLD directory of outdated backup files (ksb)
- X * remove bogus links on any age
- X * do not touch #inst$$ files unless ctime is > boot time?
- X */
- void
- Purge(pcOld, pstOld)
- char *pcOld;
- struct stat *pstOld;
- {
- X register struct direct *pDE;
- X register int i;
- X auto struct direct **ppDEDir;
- X auto char acFile[MAXPATHLEN+2], *pcLast;
- X auto int iLen;
- X auto struct stat stFile;
- X
- X iLen = MAXPATHLEN - strlen(pcOld);
- X if (iLen <= 0) {
- X fprintf(stderr, "%s: Purge: %.40s... %s\n", progname, pcOld, strerror(ENAMETOOLONG));
- X return;
- X }
- X (void)strcpy(acFile, pcOld);
- X pcLast = acFile + (MAXPATHLEN - iLen);
- X if ('/' != pcLast[-1])
- X *pcLast++ = '/', --iLen;
- X if (-1 == (i = scandir(pcOld, &ppDEDir, DotSel, (int (*)())0))) {
- X fprintf(stderr, "%s: scandir: %s: %s\n", progname, pcOld, strerror(errno));
- X return;
- X }
- X for (; i > 0; free((char *)pDE)) {
- X pDE = ppDEDir[--i];
- X if (pDE->d_namlen > iLen) {
- X fprintf(stderr, "%s: Purge: ...%s/%.20s... %s\n", progname, ((20 < MAXPATHLEN - iLen) ? pcOld : pcLast-20), pDE->d_name, strerror(ENAMETOOLONG));
- X continue;
- X }
- X (void)strcpy(pcLast, pDE->d_name);
- X if (-1 == LSTAT(acFile, & stFile)) {
- X if (errno != ENOENT) {
- X fprintf(stderr, "%s: stat: %s: %s\n", progname, acFile, strerror(errno));
- X }
- X continue;
- X }
- X switch (stFile.st_mode & S_IFMT) {
- X default:
- X fprintf(stderr, "%s: %s: is a %s?\n", progname, acFile, NodeType(stFile.st_mode, (char *)0));
- X continue;
- #if HAVE_SLINKS
- X case S_IFLNK:
- #endif
- X case S_IFREG:
- X case 0:
- X break;
- X }
- X /* if the file is a bogus link to a running program,
- X * try to remove it always...
- X */
- X if (0 == strncmp(pcLast, acBogus, iBogus)) {
- X Remove(acFile);
- X continue;
- X }
- X
- X /* if the file is a temp file used by install ignore it
- X * for at least 1 day, then remove it
- X */
- X if (0 == strncmp(pcLast, acCopy, iCopy)) {
- X if (tCopyKeep <= stFile.st_ctime) {
- X continue;
- X }
- X } else if (tCutOff <= stFile.st_ctime) {
- X continue;
- X }
- X
- X /* sticky problem -- we should not remove the evidence of a
- X * poor install (the product might still be installed in a
- X * binary directory) so we need to keep this node here...
- X * but if we find it again we can remove it, see?
- X */
- X if (stFile.st_nlink > 1) {
- X register char *pcLink;
- X
- X pcLink = FDAdd(&FDLinks, acFile, &stFile);
- X if (0 == strcmp(acFile, pcLink)) {
- X continue;
- X }
- X }
- X Remove(acFile);
- X }
- X free((char *)ppDEDir);
- }
- X
- /*
- X * scan under a directory of all the OLD dirs and purge them (ksb)
- X */
- void
- Scan(pcDir)
- char *pcDir;
- {
- X register struct direct *pDE;
- X register int i;
- X auto struct direct **ppDEDir;
- X auto char acDown[MAXPATHLEN+2], *pcLast;
- X auto struct stat stDown;
- X auto int iLen;
- X
- X if ((char *)0 == pcDir || '\000' == *pcDir)
- X pcDir = ".";
- X iLen = MAXPATHLEN - strlen(pcDir);
- X if (iLen <= 0) {
- X fprintf(stderr, "%s: Scan: %.40s... %s\n", progname, pcDir, strerror(ENAMETOOLONG));
- X return;
- X }
- X (void)strcpy(acDown, pcDir);
- X pcLast = acDown + (MAXPATHLEN - iLen);
- X if ('/' != pcLast[-1])
- X *pcLast++ = '/', --iLen;
- X if (-1 == (i = scandir(pcDir, &ppDEDir, DotSel, (int (*)())0))) {
- X fprintf(stderr, "%s: scandir: %s: %s\n", progname, pcDir, strerror(errno));
- X return;
- X }
- X for (; i > 0; free((char *)pDE)) {
- X pDE = ppDEDir[--i];
- X if (pDE->d_namlen > iLen) {
- X fprintf(stderr, "%s: Scan: ...%s/%.20s... %s\n", progname, ((20 < MAXPATHLEN - iLen) ? pcDir : pcLast-20), pDE->d_name, strerror(ENAMETOOLONG));
- X continue;
- X }
- X (void)strcpy(pcLast, pDE->d_name);
- X if (-1 == LSTAT(acDown, & stDown)) {
- X if (errno != ENOENT) {
- X fprintf(stderr, "%s: stat: %s: %s\n", progname, acDown, strerror(errno));
- X }
- X continue;
- X }
- X if (0 == strcmp(acOld, pDE->d_name)) {
- X if (isSysId((uid_t)stDown.st_uid)) {
- X Purge(acDown, & stDown);
- X }
- X continue;
- X }
- X /* if this directory an nfs (NFS) mount point?
- X * We used to use:
- X * (255 == major(stDown.st_dev))
- X */
- X if (0 != (0x80 & major(stDown.st_dev))) {
- X continue;
- X }
- X if (S_IFDIR == (stDown.st_mode & S_IFMT)) {
- X Scan(acDown);
- X }
- X }
- X free((char *)ppDEDir);
- }
- X
- /*
- X * let purge read paths to purge from find(1) output (ksb)
- X */
- static void
- DoStdin()
- {
- X static int fBeenHere = 0;
- X register char *pcNl;
- X auto char acIn[MAXPATHLEN+2];
- X auto int c;
- X
- X if (fBeenHere++) {
- X fprintf(stderr, "%s: will not recurse on stdin (skipped)\n", progname);
- X return;
- X }
- X while ((char *)0 != fgets(acIn, MAXPATHLEN+1, stdin)) {
- X if ((char *)0 == (pcNl = strchr(acIn, '\n'))) {
- X fprintf(stderr, "%s: line too long on stdin\n", progname);
- X while (EOF != (c = getc(stdin))) {
- X if ('\n' == c)
- X break;
- X }
- X continue;
- X }
- X *pcNl = '\000';
- X Which(acIn);
- X }
- X clearerr(stdin);
- X --fBeenHere;
- }
- X
- /*
- X * the user may have either given us /bin or /bin/OLD to purge. (ksb)
- X * choose the correct routine and purge it.
- X *
- X * if an old script gives us a number of days do / with that number (yucko).
- X */
- void
- Which(pcDir)
- char *pcDir;
- {
- X register char *pcSlash;
- X auto struct stat stDir;
- X
- X if (AllDigits(pcDir) && -1 == access(pcDir, 0)) {
- X fprintf(stderr, "%s: warning: old style [ndays] option\n", progname);
- X iDays = atoi(pcDir);
- X pcDir = "/";
- X }
- X if ('-' == pcDir[0] && '\000' == pcDir[1]) {
- X DoStdin();
- X return;
- X }
- X if ((char *)0 == (pcSlash = strrchr(pcDir, '/'))) {
- X pcSlash = pcDir;
- X } else {
- X ++pcSlash;
- X }
- X if (0 == strcmp(acOld, pcSlash)) {
- X if (-1 == LSTAT(pcDir, & stDir)) {
- X fprintf(stderr, "%s: stat: %s: %s\n", progname, pcDir, strerror(errno));
- X } else if (!isSysId((uid_t)stDir.st_uid)) {
- X fprintf(stderr, "%s: %s: %d: not a user to purge\n", progname, pcDir, stDir.st_uid);
- X } else {
- X Purge(pcDir, &stDir);
- X }
- X } else {
- X Scan(pcDir);
- X }
- }
- X
- /*
- X * this checks to see if we recovered from the errors we found (ksb)
- X */
- static int
- StillBad(pAE)
- AE_ELEMENT *pAE;
- {
- X auto struct stat stThis;
- X register char *pcSlash;
- X
- X if (-1 != LSTAT(pAE->pcname, &stThis) && stThis.st_nlink > 1) {
- X if ((char *)0 != (pcSlash = strrchr(pAE->pcname, '/'))) {
- X *pcSlash = '\000';
- X fprintf(stderr, "%s: %s/%s: link count %d, use `instck -i %s\' to repair\n", progname, pAE->pcname, pcSlash+1, stThis.st_nlink, pAE->pcname);
- X *pcSlash = '/';
- X } else {
- X fprintf(stderr, "%s: %s: has a link count > 1, use instck to repair\n", progname, pAE->pcname);
- X }
- X } else {
- X Remove(pAE->pcname);
- X }
- X return 0;
- }
- X
- /*
- X * When done scan any file that have bad link counts and see if we (ksB)
- X * removed the other links via purging OLD dirs
- X */
- void
- Done()
- {
- X (void)FDScan(FDLinks, StillBad);
- X
- #if defined(INST_FACILITY)
- X if (bHaveRoot && fExec) {
- X closelog();
- X }
- #endif
- }
- Purdue
- chmod 0444 purge/purge.c ||
- echo 'restore of purge/purge.c failed'
- Wc_c="`wc -c < 'purge/purge.c'`"
- test 14969 -eq "$Wc_c" ||
- echo 'purge/purge.c: original size 14969, current size' "$Wc_c"
- fi
- # ============= install.d/special.i ==============
- if test -f 'install.d/special.i' -a X"$1" != X"-c"; then
- echo 'x - skipping install.d/special.i (File already exists)'
- else
- echo 'x - extracting install.d/special.i (Text)'
- sed 's/^X//' << 'Purdue' > 'install.d/special.i' &&
- /*
- X * $Id: special.i,v 7.2 90/10/22 11:47:15 ksb Exp $
- X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
- X * 47907. All rights reserved.
- X *
- X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
- X *
- X * This software is not subject to any license of the American Telephone
- X * and Telegraph Company or the Regents of the University of California.
- X *
- X * Permission is granted to anyone to use this software for any purpose on
- X * any computer system, and to alter it and redistribute it freely, subject
- X * to the following restrictions:
- X *
- X * 1. Neither the authors nor Purdue University are responsible for any
- X * consequences of the use of this software.
- X *
- X * 2. The origin of this software must not be misrepresented, either by
- X * explicit claim or by omission. Credit to the authors and Purdue
- X * University must appear in documentation and sources.
- X *
- X * 3. Altered versions must be plainly marked as such, and must not be
- X * misrepresented as being the original software.
- X *
- X * 4. This notice may not be removed or altered.
- X */
- X
- /*
- X * this (long) C routine is expanded twice in instck, and only once
- X * in install. It is the one that searchs a config file.
- X */
- X
- #if defined(INSTCK)
- /*
- X * Scan the gien dirs for pats in the check file list? (ksb)
- X * config file format:
- X * #file mode owner group strip message
- X * /unix -r??r--r-- root * n
- X * `*' = any
- X * `"' = last
- X * `=' = the default for this col
- X * `!' = not (!mode -> not exist, !group/!owner -> any but the one listed)
- X */
- void
- DirCk(iCount, ppcDirs, pcConfig, pCL)
- int iCount; /* who many dirs to search */
- char **ppcDirs; /* dirs to search */
- #else /* install */
- void
- /*
- X * Is the named file in the check file list? If so is it OK? (ksb)
- X * FAIL is file it in list and modes are bad
- X * else SUCCESS
- X * config file format:
- X * #file mode owner group strip message
- X * /unix -r??r--r-- root * n
- X * core !r?-?--?-- * * n
- X * `*' = any
- X * `"' = last
- X * `=' = the default for this col
- X * `!' = not (!mode -> not exist, !group/!owner -> any but the one listed)
- X */
- Special(pcFile, pcConfig, pCL)
- char *pcFile; /* file we are searching for */
- #endif
- char *pcConfig; /* check list file name to read */
- CHLIST *pCL; /* pointer to the check list to build/use */
- {
- X extern char *malloc();
- X static FILE *fpCnf = (FILE *)0;
- X static char *pcCnf = "jms & ksb";
- X static char acLine[MAXCNFLINE];
- X static char acMesg[MAXCNFLINE];
- X static char acEq[] = "=", acAny[] = "*";
- X register char *pcSkip, *pcBlank;
- X register int iLine;
- #if defined(INSTCK)
- X register int i;
- X auto char *pcCurGlob;
- #else
- X auto char *pcLastComp;
- X auto char acFPath[MAXPATHLEN+1];
- #endif
- X
- X pCL->ffound = FALSE;
- X
- X if ((char *)0 == pcConfig || '\000' == pcConfig[0]) {
- #if defined(INSTCK)
- X (void)printf("%s: no configuration file\n", progname);
- #endif
- X return;
- X }
- X if (NULL == fpCnf || pcCnf != pcConfig) {
- X if (NULL != fpCnf)
- X (void)fclose(fpCnf);
- X pcCnf = pcConfig;
- X if (NULL == (fpCnf = fopen(pcCnf, "r"))) {
- X (void)fprintf(stderr, "%s: fopen (checklist): %s: %s\n", progname, pcCnf, strerror(errno));
- X exit(EXIT_OPT);
- X }
- #if defined(F_SETFD)
- X /* if we can we set the close-on-exec bit to be neat */
- X (void)fcntl(fileno(fpCnf), F_SETFD, 1);
- #endif /* have close on exec bit to twidle */
- X } else {
- X (void)rewind(fpCnf);
- X }
- X pCL->pcspecial = pcCnf;
- X
- #if defined(INSTALL)
- X if ('/' != pcFile[0]) {
- X (void)getwd(acFPath);
- X (void)strcat(acFPath, "/");
- X (void)strcat(acFPath, pcFile);
- X pcFile = CompPath(acFPath);
- X } else {
- X (void)strcpy(acFPath, pcFile); /* don't munge argument! */
- X pcFile = CompPath(acFPath);
- X }
- X
- X if ((char *)0 == (pcLastComp = strrchr(pcFile, '/'))) {
- X Die("nil pointer");
- X }
- X ++pcLastComp;
- #endif
- X
- X /* we set the defaults:
- X * not found, plain file, mode, owner, group, no strip
- X */
- X iLine = 0;
- X (void)strcpy(acLine, "* = = = =\n");
- X (void)strcpy(acMesg, "default message");
- X pCL->pcmesg = acMesg;
- X pCL->pclink = (char *)0;
- X pCL->acmode[0] = pCL->acmode[1] = '\000';
- X
- X do {
- X if ((char *)0 == (pcBlank = strchr(acLine, '\n'))) {
- X (void)fprintf(stderr, "%s: %s(%d) line too long\n", progname, pcCnf, iLine);
- X exit(EXIT_OPT);
- X }
- X do {
- X *pcBlank = '\000';
- X } while (pcBlank != acLine && (--pcBlank, isspace(*pcBlank)));
- X for (pcSkip = acLine; isspace(*pcSkip); ++pcSkip)
- X /*empty*/;
- X if ('\000' == pcSkip[0] || '#' == pcSkip[0])
- X continue;
- X
- X for (pcBlank = pcSkip; ! isspace(*pcBlank); ++pcBlank)
- X /*empty*/;
- X while (isspace(*pcBlank))
- X *pcBlank++ = '\000';
- X pCL->iline = iLine;
- X pCL->pcpat = pcSkip;
- #if defined(INSTCK)
- X pcCurGlob = pcSkip;
- #else
- X if (0 != iLine) {
- X pCL->ffound = SamePath(pcSkip, RJust(pcSkip, pcFile, pcLastComp));
- X }
- #endif
- X
- X /* mode or link */
- X pcSkip = pcBlank;
- X for (pcBlank = pcSkip; ! isspace(*pcBlank); ++pcBlank)
- X /*empty*/;
- X while (isspace(*pcBlank))
- X *pcBlank++ = '\000';
- X
- X /* file is a link */
- X if ('@' == pcSkip[0] || ':' == pcSkip[0]) {
- X pCL->pclink = strcpy(malloc(strlen(pcSkip)+1),pcSkip);
- X goto at_comment;
- X } else if ((char *)0 != pCL->pclink) {
- X free(pCL->pclink);
- X pCL->pclink = (char *)0;
- X }
- X if ('~' == pcSkip[0] || '!' == pcSkip[0] || '*' == pcSkip[0]) {
- X (void)strcpy(pCL->acmode, pcSkip);
- X if ('\000' != pcSkip[1]) {
- X CvtMode(pcSkip+1, &pCL->mmust, &pCL->moptional);
- X pCL->mtype = pCL->mmust & S_IFMT;
- X pCL->mmust &= 07777;
- X } else {
- X pCL->mtype = 0;
- X pCL->mmust = 0;
- X pCL->moptional = 0644;
- X }
- X } else if (EQUAL(pcSkip, acEq)) {
- X if ((char *)0 == DEFMODE) {
- X pCL->acmode[0] = '*';
- X } else {
- X CvtMode(DEFMODE, &pCL->mmust, &pCL->moptional);
- X pCL->acmode[0] = '\000';
- X }
- X } else if ('\"' == pcSkip[0] && '\000' == pcSkip[1]) {
- X /* use previous */;
- X } else {
- X CvtMode(pcSkip, &pCL->mmust, &pCL->moptional);
- X pCL->moptional &= 07777;
- X pCL->acmode[0] = '\000';
- X }
- X if ('\000' == pCL->acmode[0]) {
- X pCL->mtype = pCL->mmust & S_IFMT;
- X pCL->mmust &= 07777;
- X (void)NodeType(pCL->mtype, pCL->acmode);
- X }
- X if (0 == pCL->mtype) {
- X pCL->mtype = S_IFREG;
- X }
- X
- X /* owner */
- X pcSkip = pcBlank;
- X for (pcBlank = pcSkip; ! isspace(*pcBlank); ++pcBlank)
- X /*empty*/;
- X while (isspace(*pcBlank))
- X *pcBlank++ = '\000';
- X pCL->fbangowner = 0;
- X if ('!' == *pcSkip) {
- X pCL->fbangowner = 1;
- X ++pcSkip;
- X }
- X if (EQUAL(pcSkip, acEq)) {
- X if ((struct passwd *)0 != pwdDef) {
- X (void)strcpy(pCL->acowner, pwdDef->pw_name);
- X } else if ((char *)0 == DEFOWNER) {
- X (void)strcpy(pCL->acowner, acAny);
- X } else {
- X (void)strcpy(pCL->acowner, DEFOWNER);
- X }
- X } else if (! EQUAL(pcSkip, "\"")) {
- X (void)strcpy(pCL->acowner, pcSkip);
- X }
- X
- X /* group */
- X pcSkip = pcBlank;
- X for (pcBlank = pcSkip; ! isspace(*pcBlank); ++pcBlank)
- X /*empty*/;
- X while (isspace(*pcBlank))
- X *pcBlank++ = '\000';
- X pCL->fbanggroup = 0;
- X if ('!' == *pcSkip) {
- X pCL->fbanggroup = 1;
- X ++pcSkip;
- X }
- X if (EQUAL(pcSkip, acEq)) {
- X if ((struct group *)0 != grpDef) {
- X (void)strcpy(pCL->acgroup, grpDef->gr_name);
- X } else if ((char *)0 == DEFGROUP) {
- X (void)strcpy(pCL->acgroup, acAny);
- X } else {
- X (void)strcpy(pCL->acgroup, DEFGROUP);
- X }
- X } else if (! EQUAL(pcSkip, "\"")) {
- X (void)strcpy(pCL->acgroup, pcSkip);
- X }
- X
- X /* strip or not */
- X pcSkip = pcBlank;
- X for (pcBlank = pcSkip; '\000' != *pcBlank && ! isspace(*pcBlank); ++pcBlank)
- X /*empty*/;
- X while (isspace(*pcBlank))
- X *pcBlank++ = '\000';
- X if (EQUAL(pcSkip, acEq)) {
- X pCL->chstrip = CF_NONE;
- X } else switch (*pcSkip) {
- X case 's': /* yeah we should take these too */
- X case 'S':
- X pCL->chstrip = CF_STRIP;
- X break;
- X case 'l':
- X case 'L':
- X pCL->chstrip = CF_RANLIB;
- X break;
- X default:
- X (void)fprintf(stderr, "%s: unknown strip indicator `%s\'\n", progname, pcSkip);
- X /* fall through to recover */
- X case '-':
- X case 'n':
- X case 'N':
- X pCL->chstrip = CF_NONE;
- X break;
- X case '*':
- X case '\?':
- X pCL->chstrip = CF_ANY;
- X break;
- X case '\"':
- X break;
- X }
- X
- X at_comment:
- X if (! EQUAL(pcBlank, "\"")) {
- X (void)strcpy(acMesg, pcBlank);
- X }
- X
- X if (0 == iLine)
- X continue;
- X
- #if defined(INSTALL)
- X if (!pCL->ffound) {
- X continue;
- X }
- #endif
- X
- X if ('*' != pCL->acowner[0] || '\000' != pCL->acowner[1]) {
- X struct passwd *pwd;
- X if ((struct passwd *)0 != pwdDef && 0 == strcmp(pCL->acowner, pwdDef->pw_name)) {
- X pCL->uid = pwdDef->pw_uid;
- X } else if ((struct passwd *)0 == (pwd = getpwnam(pCL->acowner))) {
- X fprintf(stderr, "%s: getpwname: %s: no such user\n", progname, pCL->acowner);
- X continue;
- X } else {
- X pCL->uid = pwd->pw_uid;
- X }
- X } else if (0 != (S_ISUID & pCL->mmust)) {
- X BadSet(iLine, 'u', "user", pCL->acmode);
- X }
- X if ('*' != pCL->acgroup[0] || '\000' != pCL->acgroup[1]) {
- X struct group *grp;
- X if ((struct group *)0 != grpDef && 0 == strcmp(pCL->acgroup, grpDef->gr_name)) {
- X pCL->gid = grpDef->gr_gid;
- X } else if ((struct group *)0 == (grp = getgrnam(pCL->acgroup))) {
- X fprintf(stderr, "%s: getgrname: %s: no such group\n", progname, pCL->acgroup);
- X continue;
- X } else {
- X pCL->gid = grp->gr_gid;
- X }
- X } else if (0 != (S_ISGID & pCL->mmust)) {
- X BadSet(iLine, 'g', "group", pCL->acmode);
- X }
- X
- X ModetoStr(pCL->acmode+1, pCL->mmust, pCL->moptional);
- #if defined(INSTCK)
- X iMatches = 0;
- X if ('/' == *pcCurGlob) {
- X FileMatch(pcCurGlob+1, "/", DoCk);
- X if (0 == iMatches) {
- X NoMatches(pcCurGlob);
- X }
- X } else {
- X /* never a no-matches check here, might not have
- X * any command line dirs to search, etc [ksb]
- X */
- X for (i = 0; i < iCount; ++i) {
- X FileMatch(pcCurGlob, ppcDirs[i], DoCk);
- X }
- X }
- #else
- X if (FALSE != fVerbose || FALSE != fTrace) {
- X (void)printf("%s: found `%s\' in %s\n", progname, pcFile, pcConfig);
- X }
- X break;
- #endif
- X } while (++iLine, NULL != fgets(acLine, MAXCNFLINE, fpCnf));
- }
- Purdue
- chmod 0444 install.d/special.i ||
- echo 'restore of install.d/special.i failed'
- Wc_c="`wc -c < 'install.d/special.i'`"
- test 9712 -eq "$Wc_c" ||
- echo 'install.d/special.i: original size 9712, current size' "$Wc_c"
- fi
- # ============= purge/Makefile ==============
- if test -f 'purge/Makefile' -a X"$1" != X"-c"; then
- echo 'x - skipping purge/Makefile (File already exists)'
- else
- echo 'x - extracting purge/Makefile (Text)'
- sed 's/^X//' << 'Purdue' > 'purge/Makefile' &&
- # $Id: Makefile.plain,v 7.2 90/11/28 08:52:39 ksb Exp $
- #
- # Makefile for purge
- #
- X
- PROG= purge
- BIN= ${DESTDIR}/usr/local/etc
- MANROOT= ${DESTDIR}/usr/man
- X
- # where is the source code for install(1L)?
- INSTALLD= ../install.d
- #INSTALLD= /usr/src/usr.bin/install.d
- #INSTALLD= /usr/src/local/cmd/install.d
- X
- # which type of links to build
- #LN=ln
- LN=ln -s
- X
- L=../libopt
- #L=/usr/include/local
- I=/usr/include
- S=/usr/include/sys
- P=
- X
- INCLUDE= -I$L
- DEBUG= -O
- CDEFS=
- CFLAGS= ${DEBUG} ${CDEFS} ${INCLUDE}
- X
- LINKH= configure.h install.h
- LINKC=
- LINK= ${LINKH} ${LINKC}
- GENH= ${LINKH}
- GENC= ${LINKC}
- GEN= ${GENC} ${GENH}
- HDR= main.h purge.h filedup.h
- SRC= main.c purge.c filedup.c
- DEP= ${GENC} ${SRC}
- OBJ= main.o purge.o filedup.o
- MAN= purge.8l
- OTHER= README purge.m
- SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
- X
- all: ${PROG}
- X
- ${PROG}:$P ${OBJ}
- # ${CC} -o $@ ${CFLAGS} ${OBJ} -lopt
- # ${CC} -o $@ ${CFLAGS} ${OBJ} -L /usr/local/lib -lopt
- X ${CC} -o $@ ${CFLAGS} ${OBJ} ../libopt/libopt.a
- X
- #main.h: main.c
- #
- #main.c: ${PROG}.m
- # mkcmd std_help.m ${PROG}.m
- # -(cmp -s prog.c main.c || (cp prog.c main.c && echo main.c updated))
- # -(cmp -s prog.h main.h || (cp prog.h main.h && echo main.h updated))
- # rm -f prog.[ch]
- X
- swap: ${PROG}.m
- X mv Makefile Makefile.plain
- X mv Makefile.mkcmd Makefile
- X mkcmd std_help.m ${PROG}.m
- X -cmp -s prog.c main.c || echo main.c changed
- X -cmp -s prog.h main.h || echo main.h changed
- X rm -f prog.[ch]
- X make depend
- X
- links: ${LINK}
- X
- ${LINK}:
- X ${LN} ${INSTALLD}/$@ ./$@
- X
- clean: FRC
- X rm -f Makefile.bak ${PROG} ${GEN} *.o a.out core errs lint.out tags
- X
- calls: ${SRC} ${HDR} ${GEN} FRC
- X calls ${CDEFS} ${INCLUDE} ${DEP}
- X
- depend: ${SRC} ${HDR} ${GEN} FRC
- X maketd ${CDEFS} ${INCLUDE} ${DEP}
- X
- dirs: ${BIN}
- X
- install: all dirs FRC
- X install -cs ${PROG} ${BIN}/${PROG}
- X
- lint: ${SRC} ${HDR} ${GEN} FRC
- X lint -h ${CDEFS} ${INCLUDE} ${DEP}
- X
- mkcat: ${MAN}
- X mkcat -r${MANROOT} ${MAN}
- X
- print: source FRC
- X lpr -J'${PROG} source' ${SOURCE}
- X
- source: ${SOURCE}
- X
- spotless: clean
- X rcsclean ${SOURCE}
- X
- tags: ${HDR} ${SRC} ${GEN}
- X ctags -t ${HDR} ${SRC} ${GEN}
- X
- / ${BIN}:
- X install -dr $@
- X
- ${SOURCE}:
- X co -q $@
- X
- FRC:
- X
- # DO NOT DELETE THIS LINE - maketd DEPENDS ON IT
- X
- main.o: $L/getopt.h configure.h install.h main.c purge.h
- X
- purge.o: configure.h filedup.h install.h main.h purge.c purge.h
- X
- filedup.o: filedup.c filedup.h
- X
- # *** Do not add anything here - It will go away. ***
- Purdue
- chmod 0644 purge/Makefile ||
- echo 'restore of purge/Makefile failed'
- Wc_c="`wc -c < 'purge/Makefile'`"
- test 2355 -eq "$Wc_c" ||
- echo 'purge/Makefile: original size 2355, current size' "$Wc_c"
- fi
- # ============= install.d/TODO ==============
- if test -f 'install.d/TODO' -a X"$1" != X"-c"; then
- echo 'x - skipping install.d/TODO (File already exists)'
- else
- echo 'x - extracting install.d/TODO (Text)'
- sed 's/^X//' << 'Purdue' > 'install.d/TODO' &&
- # $Id: TODO,v 7.0 90/09/17 09:41:37 ksb Exp $
- X
- Last thing install should do:
- X
- in the configuration file one should be able to note that a file
- should be owned (grouped/moded) to the same owner (group/mode) as
- another file in the file system:
- X
- /bin/df -rwxr-s?-x root :/dev/rf0a s reads disk
- X
- let the colon indicate that it is a file to stat to get the
- group from....
- X
- kayessbee
- Purdue
- chmod 0444 install.d/TODO ||
- echo 'restore of install.d/TODO failed'
- Wc_c="`wc -c < 'install.d/TODO'`"
- test 379 -eq "$Wc_c" ||
- echo 'install.d/TODO: original size 379, current size' "$Wc_c"
- fi
- # ============= install.d/myself.cf ==============
- if test -f 'install.d/myself.cf' -a X"$1" != X"-c"; then
- echo 'x - skipping install.d/myself.cf (File already exists)'
- else
- echo 'x - extracting install.d/myself.cf (Text)'
- sed 's/^X//' << 'Purdue' > 'install.d/myself.cf' &&
- # this configuration file is used *just* to install install, itself (ksb)
- # $Id: myself.cf,v 7.0 90/10/08 11:39:55 ksb Exp $
- X
- /usr/bin/install -rwxr-xr-x root * ?
- OLD drwxr-xr-x root * -
- Purdue
- chmod 0444 install.d/myself.cf ||
- echo 'restore of install.d/myself.cf failed'
- Wc_c="`wc -c < 'install.d/myself.cf'`"
- test 232 -eq "$Wc_c" ||
- echo 'install.d/myself.cf: original size 232, current size' "$Wc_c"
- fi
- true || echo 'restore of install.d/special.c failed'
- echo End of part 4, continue with part 5
- exit 0
-
- exit 0 # Just in case...
-